'''
monitors
Author: Alex Foran
'''

import pygame,math

'''
A class to get input from standard human interface devices: keyboards, mice, joysticks, and game controllers, and consolidate all of this for easy use.

NOTE: for the purposes of the CS386 lab, the half-implemented joystick code has been removed to simplify things.
'''
class InputMonitor:
	'''
	Constructor.
	'''
	def __init__(self):
		self.statedict={}
		#set initial mouse position to the corner... it should change, anyway
		self.mousepos=(0,0)
		#initialize states
		self.lastpressed=None
		self.lastpressedframe=None
		self.mousemoved=False
	
	'''
	Processes a given event. If the given event is an input event, it is handled appropriately.
	
	Params:
	event - The pygame.event to handle.
	tolerance - deprecated
	'''
	def process_event(self,event,tolerance):
		#disabling
		if event.type==pygame.KEYUP or event.type==pygame.MOUSEBUTTONUP:
			s=self.event2str(event)
			if s in self.statedict:
				self.statedict[s].setstate(False)
			else:
				self.statedict[s]=InputTrigger(False)
		#enabling
		if event.type==pygame.KEYDOWN or event.type==pygame.MOUSEBUTTONDOWN:
			s=self.event2str(event)
			self.lastpressed=s
			self.lastpressedframe=s
			if s in self.statedict:
				self.statedict[s].setstate(True)
			else:
				self.statedict[s]=InputTrigger(True)
		#track mouse motion
		if event.type==pygame.MOUSEMOTION:
			self.mousepos=event.pos
			self.mousemoved=True
	
	'''
	Converts an event to a string for storage and reference.
	
	Params:
	event - The event.
	'''
	def event2str(self,event):
		if event.type==pygame.KEYUP or event.type==pygame.KEYDOWN:
			return pygame.key.name(event.key).upper()
		if event.type==pygame.MOUSEBUTTONDOWN or event.type==pygame.MOUSEBUTTONUP:
			return "MOUSE"+str(event.button)
	
	'''
	Clears frame states, and removes the "new" status from all current entries.
	'''
	def update(self):
		for key in self.statedict:
			self.statedict[key].new=False
		self.lastpressedframe=None
		self.mousemoved=False
	
	'''
	Returns whether the given key or button is currently pressed.
	
	Params:
	buttonstr - The string identifier for the key or button. This is always in capitals and is case-sensitive.
	'''
	def getstate(self,buttonstr,tolerance=None):
		if buttonstr in self.statedict:
			return self.statedict[buttonstr].getstate(tolerance)
		else:
			return False
	
	'''
	Returns whether the given key or button has just changed state.
	
	Params:
	buttonstr - The string identifier for the key or button. This is always in capitals and is case-sensitive.
	'''
	def getstatenew(self,buttonstr):
		if buttonstr in self.statedict:
			return self.statedict[buttonstr].new
		else:
			return False
	
	'''
	Equivalent to getstate && getstatenew
	'''
	def getjustpressed(self,buttonstr,tolerance=None):
		return (self.getstate(buttonstr,tolerance) and self.getstatenew(buttonstr))
	
'''
Holds the name, state, and "new" status for an input.
'''
class InputTrigger:
	'''
	Constructor. "new" status defaults to True.
	
	Params:
	state - The state to initialize as. Defaults to false.
	'''
	def __init__(self,state=False):
		self.state=state;
		self.new=True
	
	'''
	Sets the state and marks the status as "new".
	
	Params:
	value - The new value to hold.
	'''
	def setstate(self,value):
		self.state=value;
		self.new=True
	
	'''
	Returns the current state.
	'''
	def getstate(self,tolerance=None):
		return self.state